<?php

namespace app\websocket;

use support\Log;
use Workerman\Connection\TcpConnection;
use Workerman\Timer;

/**
 * WebSocket服务
 * 参照Java Spring WebSocket实现的功能
 */
class WebSocketServer
{
    /**
     * 存放会话对象
     * 对应Java中的 static Map<String, Session> sessionMap
     * @var array
     */
    private static array $sessionMap = [];

    /**
     * 连接建立成功调用的方法
     * 对应Java中的 @OnOpen
     *
     * @param TcpConnection $connection
     */
    public function onConnect(TcpConnection $connection): void
    {
        if (empty($sid) || $sid === 'ws') {
            $sid = 'default_' . $connection->id;
        }
        
        echo "客户端：" . $sid . "建立连接\n";
        
        // 将sid存储到连接对象中
        $connection->sid = $sid;
        Log::debug("这是链接对象" ,compact("connection"));
        // 存储会话对象
        self::$sessionMap[$sid] = $connection;
    }

    /**
     * 收到客户端消息后调用的方法
     * 对应Java中的 @OnMessage
     *
     * @param TcpConnection $connection
     * @param string $data
     */
    public function onMessage(TcpConnection $connection, string $data): void
    {
        $sid = $connection->sid ?? 'unknown';
        echo "收到来自客户端：" . $sid . "的信息:" . $data . "\n";
        
        // 这里可以添加具体的消息处理逻辑
        // 例如：解析消息类型、路由到不同的处理方法等
    }

    /**
     * 连接关闭调用的方法
     * 对应Java中的 @OnClose
     *
     * @param TcpConnection $connection
     */
    public function onClose(TcpConnection $connection): void
    {
        $sid = $connection->sid ?? 'unknown';
        echo "连接断开:" . $sid . "\n";
        
        // 从会话映射中移除
        if (isset($connection->sid)) {
            unset(self::$sessionMap[$connection->sid]);
        }
    }

    /**
     * 连接出错时调用的方法
     *
     * @param TcpConnection $connection
     * @param int $code
     * @param string $msg
     */
    public function onError(TcpConnection $connection, int $code, string $msg): void
    {
        $sid = $connection->sid ?? 'unknown';
        echo "连接错误 - 客户端：" . $sid . "，错误码：" . $code . "，错误信息：" . $msg . "\n";
    }

    /**
     * 群发消息
     * 对应Java中的 sendToAllClient 方法
     *
     * @param string $message
     */
    public static function sendToAllClient(string $message): void
    {
        foreach (self::$sessionMap as $sid => $connection) {
            try {
                // 服务器向客户端发送消息
                if ($connection && $connection->getStatus() === TcpConnection::STATUS_ESTABLISHED) {
                    $connection->send($message);
                }
            } catch (\Exception $e) {
                echo "发送消息到客户端 {$sid} 失败：" . $e->getMessage() . "\n";
                // 如果连接已断开，从映射中移除
                unset(self::$sessionMap[$sid]);
            }
        }
    }

    /**
     * 向指定客户端发送消息
     *
     * @param string $sid 客户端标识
     * @param string $message 消息内容
     * @return bool 发送是否成功
     */
    public static function sendToClient(string $sid, string $message): bool
    {
        if (!isset(self::$sessionMap[$sid])) {
            echo "客户端 {$sid} 不存在或已断开连接\n";
            return false;
        }

        $connection = self::$sessionMap[$sid];
        
        try {
            if ($connection && $connection->getStatus() === TcpConnection::STATUS_ESTABLISHED) {
                $connection->send($message);
                return true;
            } else {
                // 连接已断开，从映射中移除
                unset(self::$sessionMap[$sid]);
                return false;
            }
        } catch (\Exception $e) {
            echo "发送消息到客户端 {$sid} 失败：" . $e->getMessage() . "\n";
            unset(self::$sessionMap[$sid]);
            return false;
        }
    }

    /**
     * 获取当前连接数
     *
     * @return int
     */
    public static function getConnectionCount(): int
    {
        return count(self::$sessionMap);
    }

    /**
     * 获取所有连接的客户端ID
     *
     * @return array
     */
    public static function getAllClientIds(): array
    {
        return array_keys(self::$sessionMap);
    }

    /**
     * 检查指定客户端是否在线
     *
     * @param string $sid
     * @return bool
     */
    public static function isClientOnline(string $sid): bool
    {
        return isset(self::$sessionMap[$sid]) && 
               self::$sessionMap[$sid]->getStatus() === TcpConnection::STATUS_ESTABLISHED;
    }
}